#include "usart1.h"


/************************************************************************
*函数名：
*函数功能：
*函数参数：
*函数返回值：
*函数说明：定义系统函数
*************************************************************************/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
	USART1_SendByte((uint8_t)ch);
    return ch;
}

/************************************************************************
*函数名：USART1_Config
*函数功能：对串口1模块进行初始化配置
*函数参数：u32 bps，波特率
*函数返回值：无
*函数说明：
				USART1_TX——PA9——复用功能模式，推挽，100MHz
				USART1_RX——PA10——复用功能模式，推挽，100MHz
*************************************************************************/
static void USART1_Config(u32 bps)
{
	/*配置USART控制器*/
	//波特率寄存器
	float USART_DIV;
	u32 DIV_M;//整数部分
	u32 DIV_F;//小数部分
	USART1->CR1 = 0;
	u32 OVER8 = ((USART1->CR1)>>15);
	USART_DIV = 84000000.0/(8*bps*(2-OVER8));//APB2时钟频率84Mhz
	DIV_M = USART_DIV;
	DIV_F = (USART_DIV - DIV_M)*16;
	USART1->BRR = (DIV_M<<4|DIV_F);
	/*当波特率bps = 115200且过采样16倍时，USART_DIV ≈ 45.57，
	 * 约等于二进制的101101.1001。因此，最后给波特率寄存器所赋的值为1011011001*/

	//控制寄存器1——USART使能、发送器和接收器使能
	USART1->CR1 |= (1<<2|1<<3|1<<13);
}

/************************************************************************
*函数名：USART1_Init
*函数功能：对串口1连接的GPIO口进行初始化配置
*函数参数：无
*函数返回值：无
*函数说明：
				USART1_TX——PA9——复用功能模式，推挽，100MHz
				USART1_RX——PA10——复用功能模式，推挽，100MHz
*************************************************************************/
void USART1_Init(void)
{
	/*使能GPIOA和USART1时钟*/
	RCC->AHB1ENR |= (1<<0);//使能GPIOA时钟
	RCC->APB2ENR |= (1<<4);//使能USART1时钟

	/*配置GPIO控制器*/
	//模式寄存器——复用功能模式 10
	GPIOA->MODER &= ~(3<<9*2);
	GPIOA->MODER |= (2<<9*2);
	GPIOA->MODER &= ~(3<<10*2);
	GPIOA->MODER |= (2<<10*2);

	//输出类型寄存器——推挽 0
	GPIOA->OTYPER &= ~(3<<9);//PA9 PA10清零

	//输出速度寄存器——高速 11
	GPIOA->OSPEEDR |= (15<<9*2);

	//复用功能高位寄存器——AF7 0111
	GPIOA->AFR[1] &= ~(0xff<<4);
	GPIOA->AFR[1] |= (0x77<<4);

	/*配置USART1控制器*/
	USART1_Config(115200);//波特率设置为115200

	/*开启中断*/
	//在CR1开启接收中断
	USART1->CR1 |= (1<<5);//使能接收中断
	USART1->CR1 |= (1<<4);//使能空闲中断
	//设置中断优先级
	NVIC_SetPriority(USART1_IRQn,NVIC_EncodePriority(7-2,0,1));//给USART1设置优先级为(0,1)
	//使能中断源
	NVIC_EnableIRQ(USART1_IRQn);
}

/************************************************************************
*函数名：USART1_IRQHandler（不可更改）
*函数功能：USART1中断服务函数
*函数参数：无
*函数返回值：无
*函数说明：此函数需要用到一个USART_STRUCT结构体
*类型变量usart1_struct，且此变量在其他文件也需要使用。
*************************************************************************/
USART_STRUCT usart1_struct;

void USART1_IRQHandler(void)
{
	u8 data;

	if (USART1->SR & (1<<5))//如果是接收中断
	{
		USART1->SR &= ~(1<<5);//RXNE清零
		data = USART1->DR;//把接收到的字节数据写入变量data
		usart1_struct.recvdata[usart1_struct.count] = data;//向数据数组存入这一字节
		usart1_struct.count++;//数组下标增加
	}
	if (USART1->SR & (1<<4))//如果是空闲中断
	{
		USART1->DR;//读SR+读DR可以把IDLE清零
		usart1_struct.recvdata[usart1_struct.count] = '\0';//补充字符串末尾
		usart1_struct.count = 0;//数组下标清零
		usart1_struct.flag = 1;//数据数组已经写入完成，标志位置1
	}
}

/************************************************************************
*函数名：USART1_SendByte
*函数功能：用串口1发送一个字节的数据
*函数参数：u8 bytedata，要发送的字节
*函数返回值：无
*函数说明：
*************************************************************************/
void USART1_SendByte(u8 bytedata)
{
	while((USART1->SR & (1<<7)) == 0);//当数据未传输到发送移位寄存器时，进行循环
	USART1->DR = bytedata;
}


/************************************************************************
*函数名：USART1_SendString
*函数功能：用串口1发送一个字符串的数据
*函数参数：u8 *str，要发送的字符串
*函数返回值：无
*函数说明：
*************************************************************************/
void USART1_SendString(u8 *pstr)
{
	while(*pstr != '\0')
	{
		USART1_SendByte(*pstr);
		pstr++;
	}
}





/************************************************************************
*函数名：USART1_ReceiveByte
*函数功能：用串口1接收一个字节的数据
*函数参数：无
*函数返回值：u8 bytedata，要接收的字节
*函数说明：
*************************************************************************/
u8 USART1_ReceiveByte(void)
{
	u8 bytedata;
	while((USART1->SR & (1<<5)) == 0);//当数据未传输到RDR时，进行循环
	bytedata = USART1->DR;
	return bytedata;
}

